// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/app_list/speech_ui_model.h"

#include <stdint.h>

#include <algorithm>
#include <limits>

namespace app_list {

namespace {

    // The default sound level, just gotten from the developer device.
    const int16_t kDefaultSoundLevel = 200;

} // namespace

SpeechUIModel::SpeechUIModel()
    : is_final_(false)
    , sound_level_(0)
    , state_(app_list::SPEECH_RECOGNITION_OFF)
    , minimum_sound_level_(kDefaultSoundLevel)
    , maximum_sound_level_(kDefaultSoundLevel)
{
}

SpeechUIModel::~SpeechUIModel() { }

void SpeechUIModel::SetSpeechResult(const base::string16& result,
    bool is_final)
{
    if (result_ == result && is_final_ == is_final)
        return;

    result_ = result;
    is_final_ = is_final;
    FOR_EACH_OBSERVER(SpeechUIModelObserver,
        observers_,
        OnSpeechResult(result, is_final));
}

void SpeechUIModel::UpdateSoundLevel(int16_t level)
{
    if (sound_level_ == level)
        return;

    sound_level_ = level;

    // Tweak the sound level limits adaptively.
    // - min is the minimum value during the speech recognition starts but speech
    //   itself hasn't started.
    // - max is the maximum value when the user speaks.
    if (state_ == SPEECH_RECOGNITION_IN_SPEECH)
        maximum_sound_level_ = std::max(level, maximum_sound_level_);
    else
        minimum_sound_level_ = std::min(level, minimum_sound_level_);

    if (maximum_sound_level_ < minimum_sound_level_) {
        maximum_sound_level_ = std::max(
            static_cast<int16_t>(minimum_sound_level_ + kDefaultSoundLevel),
            std::numeric_limits<int16_t>::max());
    }

    int16_t range = maximum_sound_level_ - minimum_sound_level_;
    uint8_t visible_level = 0;
    if (range > 0) {
        int16_t visible_level_in_range = std::min(
            std::max(minimum_sound_level_, sound_level_), maximum_sound_level_);
        visible_level = (visible_level_in_range - minimum_sound_level_) * std::numeric_limits<uint8_t>::max() / range;
    }

    FOR_EACH_OBSERVER(SpeechUIModelObserver,
        observers_,
        OnSpeechSoundLevelChanged(visible_level));
}

void SpeechUIModel::SetSpeechRecognitionState(SpeechRecognitionState new_state,
    bool always_show_ui)
{
    // Don't show the speech view on a change to a network error or if the state
    // has not changed, unless |always_show_ui| is true.
    if (!always_show_ui && (state_ == new_state || new_state == SPEECH_RECOGNITION_NETWORK_ERROR)) {
        state_ = new_state;
        return;
    }

    state_ = new_state;

    // Revert the min/max sound level to the default.
    if (state_ != SPEECH_RECOGNITION_RECOGNIZING && state_ != SPEECH_RECOGNITION_IN_SPEECH) {
        minimum_sound_level_ = kDefaultSoundLevel;
        maximum_sound_level_ = kDefaultSoundLevel;
    }

    FOR_EACH_OBSERVER(SpeechUIModelObserver,
        observers_,
        OnSpeechRecognitionStateChanged(new_state));
}

void SpeechUIModel::AddObserver(SpeechUIModelObserver* observer)
{
    observers_.AddObserver(observer);
}

void SpeechUIModel::RemoveObserver(SpeechUIModelObserver* observer)
{
    observers_.RemoveObserver(observer);
}

} // namespace app_list
